package it.uniroma2.mpsr.utils;

import java.math.BigInteger;
import java.util.HashMap;

public class Misc {

	private static HashMap<Integer, BigInteger> cache = new HashMap<Integer, BigInteger>();

	public static long binomial(int N, int K) {
		long[][] binomial = new long[N+1][K+1];

		// base cases
		for (int k = 1; k <= K; k++) binomial[0][k] = 0;
		for (int n = 0; n <= N; n++) binomial[n][0] = 1;

		// bottom-up dynamic programming
		for (int n = 1; n <= N; n++)
			for (int k = 1; k <= K; k++)
				binomial[n][k] = binomial[n-1][k-1] + binomial[n-1][k];

		return binomial[N][K];
	}

	public static BigInteger factorial(int n) {
		BigInteger ret;

		if(n == 0)
			return BigInteger.ONE;
		if(null != (ret = cache.get(n)))
			return ret;
		ret = BigInteger.valueOf(n).multiply(factorial(n-1));
		cache.put(n, ret);
		return ret;
	}

	public static BigInteger betai(int n, int multiplicity) {
		if(multiplicity == 1)
			return BigInteger.ONE;
		else {
			if(n <= multiplicity) {
				return factorial(n);
			}
			else {
				return factorial(multiplicity).multiply(BigInteger.valueOf(multiplicity).pow(n - multiplicity));			
			}
		}
	}

	public static double[] solveSystem(double[][] matrix, double[] weights, int param, int paramValue) {
		double[][] coeffs = new double[matrix.length][matrix.length];
		double[] terms = new double[matrix.length];
		for (int j = 0; j < matrix.length; j++) {
			for(int i = 0; i < matrix.length; i++) {
				if(matrix[j][i] != 0) {
					coeffs[i][j] = - matrix[j][i] * weights[j];

				}
				if(i == j) {
					coeffs[i][j] += weights[i];
				}
			}
		}
		for (int j = 0; j < matrix.length; j++) {
			if(coeffs[j][param] != 0) {
				terms[j] = - coeffs[j][param] * paramValue;
				coeffs[j][param] = 0;

			}
		}
		double[] x = GaussJordanElimination.solve(coeffs, terms);
		if(x != null) {
			x[param] = paramValue;
		}

		return x;
	}
}
